/*
 * @Author: wangcb
 * @Email: wangcbgg@163.com
 * @Date: 2021-08-27 18:05:07
 * @LastEditTime: 2022-01-04 16:31:33
 * 扩展原生dom方法
 */
import cancelAFrame from "./cancelAFrame";
import requestAFrame from "./requestAFrame";
import slideOld from "./slideOld";
import { supportCss3, typeIs } from "./util";
/**
 * 扩展原生dom
 * @param {ExtendHTMLElement} target 目标dom元素
 */
export function extentDOM(target) {
    if (!target)
        return target;
    target.block = function () {
        if (!this.active())
            this.style.display = 'block';
        return this;
    };
    target.none = function () {
        if (this.active())
            this.style.display = 'none';
        return this;
    };
    target.visible = function () {
        if (!this.active())
            this.style.visibility = 'visible';
        return this;
    };
    target.unvisible = function () {
        if (this.active())
            this.style.visibility = 'hidden';
        return this;
    };
    target.active = function () {
        return this.getStyle('display') === 'block' && this.getStyle('visibility') === 'visible' && +this.getStyle('opacity') > 0;
    };
    target.setOpacity = function (opacity) {
        if (this.style.opacity !== undefined)
            this.style.opacity = '' + opacity;
        else
            this.style.filter = `alpha(opacity:${opacity * 100})`;
        return this;
    };
    target.fadeIn = function (step = 0.2) {
        if (this.active())
            return this;
        this.visible();
        this.setOpacity(0);
        let opacity = 0;
        (function render(t) {
            if (opacity < 1) {
                opacity += step;
                opacity >= 1 ? 1 : opacity;
                t.setOpacity(opacity);
                const timer = requestAFrame(() => { render(t), cancelAFrame(timer); });
            }
            else
                t.setOpacity(1);
        })(this);
        return this;
    };
    target.fadeOut = function (step = 0.2) {
        if (!this.active())
            return this;
        this.setOpacity(1);
        let opacity = 1;
        (function render(t) {
            if (opacity > 0) {
                opacity -= step;
                opacity <= 0 ? 0 : opacity;
                t.setOpacity(opacity);
                const timer = requestAFrame(() => { render(t), cancelAFrame(timer); });
            }
            else
                t.setOpacity(0);
        })(this);
        return this;
    };
    target.appendHtml = function (html) {
        if (typeof html === 'string')
            this.innerHTML += html;
        else
            this.innerHTML += html.innerHTML;
        return this;
    };
    target.prependHtml = function (html) {
        if (typeof html === 'string')
            this.innerHTML = html + this.innerHTML;
        else
            this.innerHTML = html.innerHTML + this.innerHTML;
        return this;
    };
    target.pack = function (key, val) {
        if (val !== undefined) {
            this.setAttribute('data-' + key, val);
            return val;
        }
        return this.getAttribute('data-' + key);
    };
    target.attr = function (key, val) {
        if (val !== undefined) {
            if ((key + '').toLowerCase() === 'style') {
                const style = this.style.cssText;
                if (style) { // 存在行内样式
                    const result = {};
                    const attrs = style.split(';'), newAttrs = val.split(';');
                    for (let i = 0; i < attrs.length; i++) {
                        const attr = attrs[i];
                        const kv = attr.split(':');
                        const k = kv[0], v = kv[1];
                        if (k)
                            result[k.trim()] = v?.trim();
                    }
                    for (let j = 0; j < newAttrs.length; j++) {
                        const newAttr = newAttrs[j];
                        const newKv = newAttr.split(':');
                        const newK = newKv[0], newV = newKv[1];
                        if (newK)
                            result[newK.trim()] = newV?.trim();
                    }
                    this.style.cssText = JSON.stringify(result).replace(/(":"|':')/g, ':').replace(/(","|',')/g, ';').replace(/(\"|\{|\})/g, '');
                }
                else
                    this.style.cssText = val;
            }
            else
                this.setAttribute(key, val);
            return this;
        }
        return this.getAttribute(key) || '';
    };
    target.slide = function (distance, slideDir, speed, delay, keepVal, time_function) {
        if (undefined === distance || null === distance)
            return this;
        distance = Math.round(distance);
        if (!typeIs('Number', speed))
            speed = 300;
        if (!typeIs('Number', delay))
            delay = 0;
        if (!time_function)
            time_function = 'ease';
        if (!this.forceJs && supportCss3('transform')) {
            const current = this.getTranslateVal(slideDir === 'h' ? 'x' : 'y');
            if (current === distance)
                return this;
            this.style.webkitTransition = `all ${speed}ms ${time_function} ${delay}ms`;
            this.style.transition = `all ${speed}ms ${time_function} ${delay}ms`;
            if (slideDir === 'h' || slideDir === 'h-left' || slideDir === 'h-right') {
                if (!typeIs('Number', keepVal))
                    keepVal = this.getTranslateVal('y') || 0;
                this.style.webkitTransform = `translate3d(${distance}px, ${keepVal}px, 0)`;
                this.style.transform = `translate3d(${distance}px, ${keepVal}px, 0)`;
            }
            else {
                if (!typeIs('Number', keepVal))
                    keepVal = this.getTranslateVal() || 0;
                this.style.webkitTransform = `translate3d(${keepVal}px, ${distance}px, 0)`;
                this.style.transform = `translate3d(${keepVal}px, ${distance}px, 0)`;
            }
        }
        else {
            if (slideDir === 'h' || slideDir === 'h-left' || slideDir === 'h-right') {
                const dx = this.getTranslateVal();
                if (dx === distance)
                    return this;
            }
            else {
                const dy = this.getTranslateVal('y');
                if (dy === distance)
                    return this;
            }
            switch (slideDir) {
                case 'h':
                case 'h-left':
                    slideOld(this, { left: distance, duration: speed });
                    break;
                case 'h-right':
                    slideOld(this, { right: -distance, duration: speed });
                    break;
                case 'v':
                case 'v-top':
                    slideOld(this, { top: distance, duration: speed });
                    break;
                case 'v-bottom':
                    slideOld(this, { bottom: -distance, duration: speed });
                    break;
                default:
                    slideOld(this, { top: distance, duration: speed });
                    break;
            }
        }
        return this;
    };
    target.uniformSlide = function (distance, slideDir, uniformStep = 30, cb) {
        if (!this.forceJs && supportCss3('transform')) {
            let current = this.getTranslateVal(slideDir === 'h' ? 'x' : 'y');
            if (current === distance)
                return this;
            const t = current - distance < 0 ? 1 : -1;
            let requestId = 0;
            const render = () => {
                requestId = requestAFrame(render);
                current += t * uniformStep;
                if ((t > 0 && current >= distance) || (t < 0 && current <= distance)) {
                    current = distance, cancelAFrame(requestId), cb?.(current);
                }
                if (slideDir === 'h') {
                    this.style.webkitTransform = `translate3d(${current}px,0,0)`;
                    this.style.transform = `translate3d(${current}px,0,0)`;
                }
                else {
                    this.style.webkitTransform = `translate3d(0,${current}px,0)`;
                    this.style.transform = `translate3d(0,${current}px,0)`;
                }
                this.style.webkitTransition = 'transform linear';
                this.style.transition = 'transform linear';
            };
            render();
        }
        else {
            this.slide(distance, slideDir, uniformStep * 10);
        }
        return this;
    };
    target.freeSlide = function (x, y, speed, delay, time_function) {
        if (!typeIs('Number', speed))
            speed = 300;
        if (!typeIs('Number', delay))
            delay = 0;
        if (!time_function)
            time_function = 'ease';
        if (!this.forceJs && supportCss3('transform')) {
            this.style.webkitTransition = `all ${speed}ms ${time_function} ${delay}ms`;
            this.style.transition = `all ${speed}ms ${time_function} ${delay}ms`;
            this.style.webkitTransform = `translate3d(${x}px, ${y}px, 0)`;
            this.style.transform = `translate3d(${x}px, ${y}px, 0)`;
        }
        else {
            const dx = this.getTranslateVal(), dy = this.getTranslateVal('y');
            if (dx === x && dy === y)
                return this;
            const width = parseInt(this.pack('width'), 10);
            const height = parseInt(this.pack('height'), 10);
            slideOld(this, { left: x, top: y, width, height, duration: speed });
        }
        return this;
    };
    target.bannerSlide = function (slideClass, timeout = 5000, speed = 500) {
        if (this.innerHTML.length < 0)
            return { move: () => { }, stop: () => { } };
        timeout = timeout < 1000 ? 1000 : timeout;
        if (this.forceJs || !supportCss3('transform'))
            this.style.position = 'absolute';
        this.style.width = `${this.scrollWidth}px`;
        const scroll = this.getElementsByClassName(slideClass)?.[0];
        if (!scroll || !scroll.children.length)
            return { move: () => { }, stop: () => { } };
        const render = () => {
            scroll.slide(-this.offsetHeight, 'v', speed);
            const t = setTimeout(() => {
                clearTimeout(t);
                scroll.slide(0, 'v', 0);
                const first = scroll.children[0];
                scroll.removeChild(first);
                scroll.appendChild(first);
            }, speed + 150);
        };
        let timer = 0; // 定时器
        return {
            move: () => {
                if (!timer)
                    timer = setInterval(render, timeout);
            }, stop: () => {
                if (timer)
                    clearInterval(timer), timer = 0;
            }
        };
    };
    target.getTranslateVal = function (translateDir = 'x') {
        let result = 0;
        const style = this.style;
        if (!this.forceJs && supportCss3('transform')) {
            const transform = style.webkitTransform || style.transform;
            if (!transform) { // 未设置transform
                return result;
            }
            const transformVal = transform.split('(')[1].split(')')[0].split(',');
            switch (translateDir) {
                case 'x':
                    result = parseFloat(transformVal[0] || '0');
                    break;
                case 'y':
                    result = parseFloat(transformVal[1] || '0');
                    break;
                case 'z':
                    result = parseFloat(transformVal[2] || '0');
                    break;
                default: return result;
            }
        }
        else {
            switch (translateDir) {
                case 'x':
                    result = parseFloat(this.getStyle('left') || '0');
                    break;
                case 'y':
                    result = parseFloat(this.getStyle('top') || '0');
                    break;
                case 'z': return result;
                default: return result;
            }
        }
        return result;
    };
    target.getStyle = function (prop) {
        if (this.currentStyle)
            return this.currentStyle[prop]; // @ts-ignore null表示伪元素
        return window.getComputedStyle(this, null)[prop];
    };
    target.transitionStart = function (callback) {
        this.addEventListener('webkitTransitionStart', (ev) => { callback(ev); }, false);
        this.addEventListener('transitionstart', (ev) => { callback(ev); }, false);
        return this;
    };
    target.transitionRun = function (callback) {
        this.addEventListener('webkitTransitionRun', (ev) => { callback(ev); }, false);
        this.addEventListener('transitionrun', (ev) => { callback(ev); }, false);
        return this;
    };
    target.transitionEnd = function (callback) {
        this.addEventListener('webkitTransitionEnd', (ev) => { callback(ev); }, false);
        this.addEventListener('transitionend', (ev) => { callback(ev); }, false);
        return this;
    };
    target.doForceJs = function () {
        this.forceJs = true;
        return this;
    };
    target.undoForceJs = function () {
        this.forceJs = false;
        return this;
    };
    return target;
}
export default extentDOM;
